package com.timing.finder.framework;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

import java.nio.charset.StandardCharsets;

/**
 * 布隆过滤器
 *
 * @author JingGe(* ^ ▽ ^ *)
 * @date 2023-03-19 15:36
 * @email 1158055613@qq.com
 */
public class StorableBloomFilter {
    private BloomFilter<String> bloomFilter;
    private TimingFinderConfig config;
    private CacheRepository cacheRepository;

    @SuppressWarnings("unchecked")
    public static StorableBloomFilter loadFromCache(CacheRepository cacheRepository, TimingFinderConfig config) {
        BloomFilter<String> filter = cacheRepository.get(TimingFinderConstant.BLOOM_CACHE_KEY + config.applicationName, BloomFilter.class);
        if (filter == null) {
            return null;
        }
        StorableBloomFilter storableBloomFilter = new StorableBloomFilter();
        storableBloomFilter.bloomFilter = filter;
        storableBloomFilter.config = config;
        storableBloomFilter.cacheRepository = cacheRepository;
        return storableBloomFilter;
    }

    public static boolean isInCache(CacheRepository cacheRepository, String applicationName) {
        return cacheRepository.isExist(TimingFinderConstant.BLOOM_CACHE_KEY + applicationName);
    }

    public StorableBloomFilter(TimingFinderConfig config, CacheRepository cacheRepository) {
        if (config == null) {
            throw new NullPointerException("配置为null");
        }
        this.config = config;
        this.bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), config.bloomExpectedInsertions, config.bloomMisjudgmentRate);
        this.cacheRepository = cacheRepository;
    }

    private StorableBloomFilter() {
    }

    public boolean mightContains(String key) {
        return bloomFilter.mightContain(key);
    }

    public void put(String key) {
        bloomFilter.put(key);
    }

    public double misjudgmentRate() {
        return bloomFilter.expectedFpp();
    }

    public BloomFilter<String> getBloomFilter() {
        return bloomFilter;
    }

    public void clean() {
        this.bloomFilter = null;
    }

    public boolean storeInCache() {
        return cacheRepository.set(TimingFinderConstant.BLOOM_CACHE_KEY + config.applicationName, bloomFilter);
    }
}
